﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using TCC.CMFlow.Models;
using TCC.CMFlow.Contexts;

namespace TCC.CMFlow.Controllers
{
    [Authorize]
    public class GrupoAprovacaoController : Controller
    {
        private DataContext db = new DataContext();

        // GET: /GrupoAprovacao/
        [AuthorizeUserAttribute(Modulo = eModulosSistema.GruposAprovacao)]
        public ActionResult Index()
        {
            var usuarios = db.Users.Where(Usuario.IsAtivoExpression).ToList();
            ViewBag.GrupoUsuario = new SelectList(usuarios, "Id", "Nome");

            return View(db.GrupoAprovacao);
        }

        [AuthorizeUserAttribute(Modulo = eModulosSistema.GruposAprovacao, Permissao = ePermissoes.Consultar)]
        public ActionResult Search(string ID, string nome, string GrupoUsuario)
        {
            long _ID;
            long.TryParse(ID, out _ID);

            var usuarios = db.Users.Where(Usuario.IsAtivoExpression).ToList();
            ViewBag.GrupoUsuario = new SelectList(usuarios, "Id", "Nome", GrupoUsuario);

            var grupos = from g in db.GrupoAprovacao
                         select g;

            if (_ID > 0)
            {
                grupos = grupos.Where(g => g.ID == _ID);
            }

            if (!String.IsNullOrEmpty(nome))
            {
                grupos = grupos.Where(g => g.Nome.ToUpper().Contains(nome.ToUpper()));
            }

            if (!String.IsNullOrEmpty(GrupoUsuario))
            {
                grupos = grupos.Where(g => g.Usuarios.Select(u => u.Id).Contains(GrupoUsuario));
            }

            return View("Index", grupos.ToList());
        }

        [AuthorizeUserAttribute(Modulo = eModulosSistema.GruposAprovacao, Permissao = ePermissoes.Visualizar)]
        // GET: /GrupoAprovacao/Details/5
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            GrupoAprovacao grupoaprovacao = db.GrupoAprovacao.Find(id);
            if (grupoaprovacao == null)
            {
                return HttpNotFound();
            }
            return View(grupoaprovacao);
        }

        [AuthorizeUserAttribute(Modulo = eModulosSistema.GruposAprovacao, Permissao = ePermissoes.Incluir, isModal = true)]
        // GET: /GrupoAprovacao/Create
        public ActionResult Create()
        {
            var usuarios = db.Users.Where(Usuario.IsAtivoExpression).ToList();
            ViewBag.GrupoUsuarios = new MultiSelectList(usuarios, "Id", "Nome");

            return PartialView();
        }

        // POST: /GrupoAprovacao/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "ID,Nome,Descricao,InicioVigencia,FimVigencia")] GrupoAprovacao grupoaprovacao, string[] GrupoUsuariosList)
        {
            if (ModelState.IsValid)
            {
                if (GrupoUsuariosList != null)
                {
                    var usuariosSelecionados = (from p in db.Users
                                                where GrupoUsuariosList.Contains(p.Id)
                                                select p).ToList();

                    grupoaprovacao.Usuarios = usuariosSelecionados;
                }

                db.GrupoAprovacao.Add(grupoaprovacao);
                db.SaveChanges();

                return Json(new { success = true });
            }

            var usuarios = db.Users.Where(Usuario.IsAtivoExpression).ToList();
            ViewBag.GrupoUsuarios = new MultiSelectList(usuarios, "Id", "Nome");

            return View(grupoaprovacao);
        }

        [AuthorizeUserAttribute(Modulo = eModulosSistema.GruposAprovacao, Permissao = ePermissoes.Editar, isModal = true)]
        // GET: /GrupoAprovacao/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            GrupoAprovacao grupoaprovacao = db.GrupoAprovacao.Find(id);
            if (grupoaprovacao == null)
            {
                return HttpNotFound();
            }
            return PartialView(grupoaprovacao);
        }

        // POST: /GrupoAprovacao/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "ID,Nome,Descricao,InicioVigencia,FimVigencia", Exclude = "Usuarios")] GrupoAprovacao grupoaprovacao)
        {
            if (ModelState.IsValid)
            {
                db.Entry(grupoaprovacao).State = EntityState.Modified;
                db.SaveChanges();

                return Json(new { success = true });
            }
            return PartialView(grupoaprovacao);
        }

        // GET: /CategoriaWorkflow/Delete/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Excluir, isModal = true)]
        public ActionResult Inactivate(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            GrupoAprovacao grupoaprovacao = db.GrupoAprovacao.Find(id);
            if (grupoaprovacao == null)
            {
                return HttpNotFound();
            }
            return PartialView(grupoaprovacao);
        }

        // POST: /CategoriaWorkflow/Inactivate/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Inactivate(int id, DateTime? FimVigencia)
        {
            if (FimVigencia < DateTime.Today)
            {
                ModelState.AddModelError("Date", "O fim da vigência não pode ser retroativo.");
                return PartialView();
            }

            GrupoAprovacao grupoaprovacao = db.GrupoAprovacao.Find(id);
            if (grupoaprovacao.InicioVigencia > FimVigencia)
            {
                ModelState.AddModelError("Date", "Data fim não pode ser menor que a data início.");
                return PartialView();
            }

            if (ModelState.IsValid)
            {
                grupoaprovacao.FimVigencia = FimVigencia;

                db.Entry(grupoaprovacao).State = EntityState.Modified;
                db.SaveChanges();
                return Json(new { success = true });
            }
            return PartialView(grupoaprovacao);
        }

        [AuthorizeUserAttribute(Modulo = eModulosSistema.GruposAprovacao, Permissao = ePermissoes.Excluir)]
        // GET: /GrupoAprovacao/Delete/5
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            GrupoAprovacao grupoaprovacao = db.GrupoAprovacao.Find(id);
            if (grupoaprovacao == null)
            {
                return HttpNotFound();
            }
            return View(grupoaprovacao);
        }

        // POST: /GrupoAprovacao/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            GrupoAprovacao grupoaprovacao = db.GrupoAprovacao.Find(id);
            db.GrupoAprovacao.Remove(grupoaprovacao);
            db.SaveChanges();

            return RedirectToAction("Index");
        }

        [AuthorizeUserAttribute(Modulo = eModulosSistema.GruposAprovacao, Permissao = ePermissoes.Editar, isModal = true)]
        // GET: /GrupoAprovacao/AdicionarUsuario/5
        public ActionResult AdicionarUsuario(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            GrupoAprovacao grupoaprovacao = db.GrupoAprovacao.Find(id);
            if (grupoaprovacao == null)
            {
                return HttpNotFound();
            }

            var usuarios = RetornaUsuariosNaoAdicionados(grupoaprovacao.Usuarios);
            ViewBag.GrupoUsuarios = new MultiSelectList(usuarios, "Id", "Nome");

            return PartialView(grupoaprovacao);
        }

        // POST: /GrupoAprovacao/AdicionarUsuario/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult AdicionarUsuario(int? id, string[] GrupoUsuariosList)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            GrupoAprovacao grupoaprovacao = db.GrupoAprovacao.Find(id);
            if (grupoaprovacao == null)
            {
                return HttpNotFound();
            }

            if (GrupoUsuariosList == null)
            {
                ModelState.AddModelError("User", "Nenhum Usuário foi selecionado.");

                var usuarios = RetornaUsuariosNaoAdicionados(grupoaprovacao.Usuarios);
                ViewBag.GrupoUsuarios = new MultiSelectList(usuarios, "Id", "Nome");

                return PartialView(grupoaprovacao);
            }

            var usuariosSelecionados = (from p in db.Users
                                        where GrupoUsuariosList.Contains(p.Id)
                                        select p).ToList();
            usuariosSelecionados.ForEach(u => grupoaprovacao.Usuarios.Add(u));
            db.SaveChanges();

            return Json(new { success = true });
        }

        [AuthorizeUserAttribute(Modulo = eModulosSistema.GruposAprovacao, Permissao = ePermissoes.Editar, isModal = true)]
        // GET: /GrupoAprovacao/DeletarUsuario/5
        public ActionResult DeletarUsuario(int? id, string grupoUsuarioId)
        {
            if (id == null || grupoUsuarioId == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            GrupoAprovacao grupoAprovacao = db.GrupoAprovacao.Find(id);
            if (grupoAprovacao == null)
            {
                return HttpNotFound();
            }

            var usuario = grupoAprovacao.Usuarios.Where(u => u.Id == grupoUsuarioId).FirstOrDefault();

            return PartialView(usuario);
        }

        // POST: /GrupoAprovacao/DeletarUsuario/5
        [HttpPost, ActionName("DeletarUsuario")]
        [ValidateAntiForgeryToken]
        public ActionResult DeletarUsuarioConfirmado(int id, string grupoUsuarioId)
        {
            GrupoAprovacao grupoaprovacao = db.GrupoAprovacao.Find(id);
            var usuario = grupoaprovacao.Usuarios.Where(u => u.Id == grupoUsuarioId).FirstOrDefault();

            if (this.ExisteCategoriaGrupoUsuario(id, grupoUsuarioId))
            {
                ModelState.AddModelError("GrupoUser", "Este usuário está associado a uma lista de aprovação para Categorias de Workflow");

                return PartialView(usuario);
            }

            grupoaprovacao.Usuarios.Remove(usuario);
            db.SaveChanges();

            return Json(new { success = true });
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }

        private List<Usuario> RetornaUsuariosNaoAdicionados(ICollection<Usuario> usuariosAdicionados)
        {
            var usuariosAtivos = db.Users.Where(Usuario.IsAtivoExpression).ToList();
            var usuarios = usuariosAtivos.Except(usuariosAdicionados, new LambdaComparer<Usuario>((a, b) => a.Codigo == b.Codigo, a => (int)a.Codigo)).ToList();

            return usuarios;
        }

        private bool ExisteCategoriaGrupoUsuario(int grupoAprovacaoID, string usuarioId)
        {
            return db.CategoriaWorkflow.SelectMany(c => c.CategoriaGrupos)
                                       .Where(cg => cg.GrupoAprovacaoID == grupoAprovacaoID)
                                       .SelectMany(g => g.Usuarios)
                                       .Any(u => u.Id == usuarioId);
        }
    }
}
